mod memory;

use std::{future::Future, pin::Pin, sync::Arc};

use ::oauth2::{AccessToken, CsrfToken, PkceCodeVerifier, RefreshToken};
use chrono::{DateTime, Utc};

use serde::{Serialize, Deserialize};


#[derive(Serialize, Deserialize, Debug)]
pub struct AuthInfo {
    pub csrf_token: CsrfToken,
    pub pkce_verifier: PkceCodeVerifier,
    pub return_uri: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserData {
    pub phone: Option<String>,
    pub name: Option<String>,
    pub email: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TokenInfo {
    pub access_token: AccessToken,
    pub refresh_token: Option<RefreshToken>,
    pub expires: DateTime<Utc>,
    pub user_data: UserData,
}


pub trait AuthStore: Send + Sync {
    fn set_auth(&self, uid: &str, info: AuthInfo) -> Pin<Box<dyn Future<Output=()> + Send>>;
    fn remove_auth(&self, uid: &str) -> Pin<Box<dyn Future<Output=Option<AuthInfo>> + Send>>;
    fn set_token_info(&self, uid: &str, info: TokenInfo) -> Pin<Box<dyn Future<Output=()> + Send>>;
    fn get_token_info(&self, uid: &str) -> Pin<Box<dyn Future<Output=Option<TokenInfo>> + Send>>;
}


#[derive(Deserialize, Debug)]
pub enum AuthStoreConfig {
    #[serde(rename="in_memory")]
    InMemory,
}


pub fn create_auth_store(config: AuthStoreConfig) -> Arc<dyn AuthStore> {
    match config {
        AuthStoreConfig::InMemory => Arc::new(memory::MemoryAuthStore::new())
    }
}